﻿/*
* This software is the confidential and proprietary
* information of NetBay
* Such confidential information should not be disclosed
* NetBay copyright(c) 
*/
#region Using
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using NetBay.Core.DataAccess;
using NetBay.Core.Extensions;
using NetBay.Core.Log;
using NetBay.Core.BusinessEntities.Workflow;

#endregion

namespace Rio.Flow.DataAccess
{
    public partial class DA_WorkflowDefinition
    {
        #region Enum
        /// <summary>
        /// List of DB functions to access data
        /// </summary>
        private enum DbFunction
        {
            [DescriptionAttribute("")]
            None,
            [DescriptionAttribute("P_WKF_DEF_Get")]
            GetDefinitions,
            [DescriptionAttribute("P_WKF_DEF_Get_ByName")]
            GetDefinitionByName,
            [DescriptionAttribute("P_WKF_DEF_Get_ById")]
            GetDefinitionById,
            [DescriptionAttribute("P_WKF_DEF_Get_Child_ById")]
            GetDefinitionChildById,
            [DescriptionAttribute("P_WKF_DEF_Get_ByFldTypeId")]
            GetDefinitionByFolderTypeId,
            [DescriptionAttribute("P_WKF_DEF_ACT_Get_ById")]
            GetDefinitionActions,
            [DescriptionAttribute("P_WKF_DEF_COND_Get_ById")]
            GetDefinitionConditions,
            [DescriptionAttribute("P_WKF_DEF_Add")]
            AddWorkflowDefinition,
            [DescriptionAttribute("P_WKF_DEF_Del")]
            DeleteDefinition,
            [DescriptionAttribute("P_WKF_DEF_Deactivate")]
            DeactivateDefinition,
            [DescriptionAttribute("P_WKF_DEF_ACT_COND_Add")]
            AddActionOrCondition,
            [DescriptionAttribute("P_WKF_DEF_REC_Add")]
            AddReceiver,
            [DescriptionAttribute("P_WKF_DEF_REC_Get_ById")]
            GetReceiversById,
            [DescriptionAttribute("P_WKF_DEF_LINK_Del")]
            DeleteDefinitionLink,
            [DescriptionAttribute("P_WKF_DEF_LINK_Upd")]
            UpdateDefinitionLink,
            [DescriptionAttribute("P_WKF_DEF_Group_Get")]
            GetReceiversGroupId,
            [DescriptionAttribute("P_WKF_DEF_Upt_ParentId")]
            UpdateParentId,
        }

        #endregion

        #region Public functions

        /// <summary>
        /// Calls P_WKF_DEF_Get stored procedure
        /// </summary>
        /// <returns></returns>
        public static IDataReader GetWorkflowDefinitions()
        {
            LogManager.Instance().LogDebug("...");

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitions.szGetDescription());

            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Get_ById stored procedure
        /// </summary>
        /// <param name="wkfDefinitionId">The WKF definition id.</param>
        /// <returns></returns>
        public static IDataReader GetWorkflowDefinitionById(long wkfDefinitionId)
        {
            LogManager.Instance().LogDebugFormat("(wkfDefinitionId<{0}>)...", wkfDefinitionId);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitionById.szGetDescription());
            db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefinitionId);

            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Child_Get_ById stored procedure
        /// </summary>
        /// <param name="wkfDefinitionParentId">The WKF definition parent id.</param>
        /// <returns></returns>
        public static IDataReader GetWorkflowDefinitionChildById(long wkfDefinitionParentId)
        {
            LogManager.Instance().LogDebugFormat("(wkfDefinitionParentId<{0}>)...", wkfDefinitionParentId);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitionChildById.szGetDescription());
            db.AddInParameter(dbCommand, "p_lParentId", DbType.Int64, wkfDefinitionParentId);
            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Get_ByName stored procedure
        /// </summary>
        /// <param name="wkfDefinitionName">Name of the WKF definition.</param>
        /// <returns></returns>
        public static IDataReader GetWorkflowDefinitionByName(string wkfDefinitionName)
        {
            LogManager.Instance().LogDebugFormat("(wkfDefinitionName<{0}>)...", wkfDefinitionName);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitionByName.szGetDescription());
            db.AddInParameter(dbCommand, "p_sWkfDefName", DbType.String, wkfDefinitionName);

            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Get_ByFldTypeId stored procedure
        /// </summary>
        /// <param name="wkfModelName">Workflow model name</param>
        /// <returns></returns>
        public static IDataReader GetWorkflowDefinitionsByFolderTypeId(long folderTypeIndentifier)
        {
            LogManager.Instance().LogDebugFormat("(folderTypeIndentifier<{0}>)...", folderTypeIndentifier);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitionByFolderTypeId.szGetDescription());
            db.AddInParameter(dbCommand, "p_lFolderTypeId", DbType.Int64, folderTypeIndentifier);

            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_ACT_Get_ById stored procedure
        /// </summary>
        /// <param name="wkfDefinitionID">The WKF definition ID.</param>
        /// <returns></returns>
        public static IDataReader GetActions(long wkfDefinitionID)
        {
            LogManager.Instance().LogDebugFormat("(wkfDefinitionID<{0}>)...", wkfDefinitionID);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitionActions.szGetDescription());
            db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefinitionID);

            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_COND_Get_ById stored procedure
        /// </summary>
        /// <param name="wkfDefinitionID">The WKF definition ID.</param>
        /// <returns></returns>
        public static IDataReader GetConditions(long wkfDefinitionID)
        {
            LogManager.Instance().LogDebugFormat("(wkfDefinitionID<{0}>)...", wkfDefinitionID);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetDefinitionConditions.szGetDescription());
            db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefinitionID);

            return db.ExecuteReader(dbCommand);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Add stored procedure
        /// </summary>
        /// <param name="definition">The definition.</param>
        /// <param name="actions">The actions.</param>
        /// <param name="conditions">The conditions.</param>
        /// <param name="groupIds">The group ids.</param>
        /// <returns></returns>
        public static bool AddWorkflowDefinition(WorkflowDefinition definition, Dictionary<long, bool> actions, List<long> conditions, List<long> groupIds, bool keepChilds = true)
        {
            return internalAddWorkflowDefinition(definition, actions, conditions, null, groupIds, keepChilds);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Add stored procedure
        /// </summary>
        /// <param name="definition">The definition.</param>
        /// <param name="actions">The actions.</param>
        /// <param name="conditions">The conditions.</param>
        /// <param name="indexIdentifier">The index identifier.</param>
        /// <returns></returns>
        public static bool AddWorkflowDefinition(WorkflowDefinition definition, Dictionary<long, bool> actions, List<long> conditions, long indexIdentifier, bool keepChilds = true)
        {
            return internalAddWorkflowDefinition(definition, actions, conditions, indexIdentifier, null, keepChilds);
        }

        /// <summary>
        /// Calls P_WKF_DEF_Del stored procedure
        /// </summary>
        /// <param name="wkfDefId">Workflow definition identifier</param>
        /// <returns>True if ok</returns>
        public static bool DeleteDefinition(long wkfDefId)
        {
            var l_bReturn = true;
            try
            {
                LogManager.Instance().LogDebug("(wkkDefId<" + wkfDefId + ">)");

                var db = DbHelper.DataBase;
                using (var dbCommand = db.GetNewCommand(DbFunction.DeleteDefinition.szGetDescription(), false))
                {
                    db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefId);

                    db.ExecuteNonQuery(dbCommand);
                }
            }
            catch (Exception ex)
            {
                l_bReturn = false;
                LogManager.Instance().LogError("Exception -> " + Environment.NewLine + ex.Message);
            }
            return l_bReturn;
        }

        /// <summary>
        /// Calls P_WKF_DEF_Deactivate stored procedure
        /// </summary>
        /// <param name="wkfDefId">Workflow definition identifier</param>
        /// <param name="deactivationDate">The deactivation date.</param>
        /// <returns>
        /// True if ok
        /// </returns>
        public static bool DeactivateDefinition(long wkfDefId, DateTime deactivationDate)
        {
            var l_bReturn = true;
            try
            {
                LogManager.Instance().LogDebug("(wkkDefId<" + wkfDefId + ">)");

                var db = DbHelper.DataBase;
                using (var dbCommand = db.GetNewCommand(DbFunction.DeactivateDefinition.szGetDescription(), false))
                {
                    db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefId);
                    db.AddInParameter(dbCommand, "p_dDeactivationDate", DbType.DateTime, deactivationDate.Date);

                    db.ExecuteNonQuery(dbCommand);
                }
            }
            catch (Exception ex)
            {
                l_bReturn = false;
                LogManager.Instance().LogError("Exception -> " + Environment.NewLine + ex.Message);
            }
            return l_bReturn;
        }

        /// <summary>
        /// Calls P_WKF_MODEL_ACT_COND_Add stored procedure
        /// </summary>
        /// <param name="wkfDefId">Workflow definition identifier</param>
        /// <param name="wkfActCondId">Model condition or action identifier</param>
        /// <returns>True if ok</returns>
        public static bool AddActionOrConditionToDefinition(long wkfDefId, long wkfActCondId, bool isTrigger = false)
        {
            var l_bReturn = true;
            try
            {
                LogManager.Instance().LogDebug("(wkkDefId<" + wkfDefId + "> wkfActCondId<" + wkfActCondId + ">isTrigger<" + isTrigger.ToString() + ">)");

                var db = DbHelper.DataBase;
                using (var dbCommand = db.GetNewCommand(DbFunction.AddActionOrCondition.szGetDescription(), false))
                {
                    db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefId);
                    db.AddInParameter(dbCommand, "p_lWkfActCondId", DbType.Int64, wkfActCondId);
                    db.AddInParameter(dbCommand, "p_iIsTrigger", DbType.Int32, Convert.ToInt32(isTrigger));

                    db.ExecuteNonQuery(dbCommand);
                }
            }
            catch (Exception ex)
            {
                l_bReturn = false;
                LogManager.Instance().LogError("Exception -> " + Environment.NewLine + ex.Message);
            }
            return l_bReturn;
        }

        /// <summary>
        /// Calls P_WKF_MODEL_ACT_COND_Add stored procedure
        /// </summary>
        /// <param name="wkfDefId">Workflow definition identifier</param>
        /// <param name="groupId"></param>
        /// <returns>True if ok</returns>
        public static bool AddReceiver(long wkfDefId, long groupId)
        {
            var l_bReturn = true;
            try
            {
                LogManager.Instance().LogDebug("(wkfDefId<" + wkfDefId + "> groupId<" + groupId + ">)");

                var db = DbHelper.DataBase;
                using (var dbCommand = db.GetNewCommand(DbFunction.AddReceiver.szGetDescription(), false))
                {
                    db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefId);
                    db.AddInParameter(dbCommand, "p_lRgId", DbType.Int64, groupId);

                    db.ExecuteNonQuery(dbCommand);
                }
            }
            catch (Exception ex)
            {
                l_bReturn = false;
                LogManager.Instance().LogError("Exception -> " + Environment.NewLine + ex.Message);
            }
            return l_bReturn;
        }

        /// <summary>
        /// Calls P_WKF_MODEL_ACT_COND_Add stored procedure
        /// </summary>
        /// <param name="wkfDefId">The WKF def id.</param>
        /// <returns></returns>
        public static IDataReader GetReceiversGroupId(long wkfDefId)
        {
            LogManager.Instance().LogDebugFormat("(wkfDefId<{0}>)...", wkfDefId);

            var db = DbHelper.DataBase;
            var dbCommand = db.GetNewCommand(DbFunction.GetReceiversGroupId.szGetDescription());
            db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, wkfDefId);

            return db.ExecuteReader(dbCommand);
        }

        #endregion

        #region Private functions

        /// <summary>
        /// Internals the add workflow definition.
        /// </summary>
        /// <param name="definition">The definition.</param>
        /// <param name="actions">The actions.</param>
        /// <param name="conditions">The conditions.</param>
        /// <param name="receiverIndexId">The receiver index id.</param>
        /// <param name="groupIds">The group ids.</param>
        /// <param name="keepChilds">if set to <c>true</c> [keep childs].</param>
        /// <returns></returns>
        private static bool internalAddWorkflowDefinition(WorkflowDefinition definition,
                                                          Dictionary<long, bool> actions,
                                                          List<long> conditions,
                                                          long? receiverIndexId,
                                                          List<long> groupIds,
                                                          bool keepChilds = true)
        {
            var l_bReturn = true;
            DbTransaction transaction = null;
            var db = DbHelper.DataBase;
            LogManager.Instance().LogDebug("...");

            using (DbConnection connection_db_b = db.CreateConnection())
            {
                try
                {
                    connection_db_b.Open();
                    transaction = connection_db_b.BeginTransaction();

                    //Add definition
                    var dbCommand = db.GetNewCommand(DbFunction.AddWorkflowDefinition.szGetDescription());
                    db.AddInParameter(dbCommand, "p_lWkfTypeId", DbType.Int64, Convert.ToInt64(definition.WorkflowType));
                    db.AddInParameter(dbCommand, "p_sWkflDefName", DbType.String, definition.Name);
                    db.AddInParameter(dbCommand, "p_sWkflDefDesc", DbType.String, definition.Description);
                    db.AddInParameter(dbCommand, "p_sWkflDefClassname", DbType.String, definition.ClassName);
                    db.AddInParameter(dbCommand, "p_sWkflDefAssembly", DbType.String, definition.AssemblyName);
                    db.AddInParameter(dbCommand, "p_sWkflDefRules", DbType.AnsiString, definition.Rules);
                    db.AddInParameter(dbCommand, "p_lTdId", DbType.Int64, definition.FolderTypeId);
                    db.AddInParameter(dbCommand, "p_dStartDate", DbType.DateTime, definition.StartDate.Date);
                    db.AddInParameter(dbCommand, "p_lWkfRecModeId", DbType.Int64, Convert.ToInt64(definition.ReceiversType));
                    db.AddInParameter(dbCommand, "p_rp_ch_no_receiver", DbType.Int64, receiverIndexId);
                    db.AddInParameter(dbCommand, "p_lWkfMdlId", DbType.Int64, definition.ModelId);
                    db.AddInParameter(dbCommand, "p_iHierarchical", DbType.Int64, Convert.ToInt64(definition.IsHierarchical));


                    if (definition.EndDate.HasValue)
                        db.AddInParameter(dbCommand, "p_dEndDate", DbType.DateTime, definition.EndDate.Value.Date);
                    else
                        db.AddInParameter(dbCommand, "p_dEndDate", DbType.DateTime, DBNull.Value);

                    if (definition.ParentId != null && definition.ParentId > 0)
                        db.AddInParameter(dbCommand, "p_lWkfDefParentId", DbType.Int64, Convert.ToInt64(definition.ParentId));
                    else
                        db.AddInParameter(dbCommand, "p_lWkfDefParentId", DbType.Int64, DBNull.Value);

                    int newDefinitionIdentifier = 0;
                    using (IDataReader reader = db.ExecuteReader(dbCommand, transaction))
                    {
                        while (reader.Read())
                        {
                            newDefinitionIdentifier = Convert.ToInt32(reader["WKF_DEF_ID"]);
                        }
                    }

                    //Add Actions
                    LogManager.Instance().LogDebug("Adding Actions...");
                    foreach (KeyValuePair<long, bool> item in actions)
                    {
                        dbCommand = db.GetNewCommand(DbFunction.AddActionOrCondition.szGetDescription(), false);
                        db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, newDefinitionIdentifier);
                        db.AddInParameter(dbCommand, "p_lWkfActCondId", DbType.Int64, item.Key);
                        db.AddInParameter(dbCommand, "p_iIsTrigger", DbType.Int32, Convert.ToInt32(item.Value));
                        db.ExecuteNonQuery(dbCommand, transaction);
                    }

                    //Add Conditions
                    LogManager.Instance().LogDebug("Adding Conditions...");
                    foreach (var id in conditions)
                    {
                        dbCommand = db.GetNewCommand(DbFunction.AddActionOrCondition.szGetDescription(), false);
                        db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, newDefinitionIdentifier);
                        db.AddInParameter(dbCommand, "p_lWkfActCondId", DbType.Int64, id);
                        db.AddInParameter(dbCommand, "p_iIsTrigger", DbType.Int32, 1);
                        db.ExecuteNonQuery(dbCommand, transaction);
                    }

                    //Add Receivers
                    LogManager.Instance().LogDebug("Adding Receivers...");
                    if (groupIds != null)
                    {
                        foreach (var id in groupIds)
                        {
                            dbCommand = db.GetNewCommand(DbFunction.AddReceiver.szGetDescription(), false);
                            db.AddInParameter(dbCommand, "p_lWkfDefId", DbType.Int64, newDefinitionIdentifier);
                            db.AddInParameter(dbCommand, "p_lRgId", DbType.Int64, id);
                            db.ExecuteNonQuery(dbCommand, transaction);
                        }
                    }

                    //Update ParentIds
                    if (keepChilds)
                    {
                        dbCommand = db.GetNewCommand(DbFunction.UpdateParentId.szGetDescription(), false);
                        db.AddInParameter(dbCommand, "p_lWkfOldDefId", DbType.Int64, definition.Identifier);
                        db.AddInParameter(dbCommand, "p_lWkfNewParentId", DbType.Int64, newDefinitionIdentifier);
                        db.ExecuteNonQuery(dbCommand, transaction);
                    }


                    transaction.Commit();
                }
                catch (Exception ex)
                {
                    LogManager.Instance().LogError("Exception -> " + Environment.NewLine + ex.Message);

                    if (transaction != null)
                    {
                        transaction.Rollback();
                        LogManager.Instance().LogInfo("Rollback() executed...");
                    }

                    l_bReturn = false;
                }
            }

            return l_bReturn;
        }
        #endregion
    }
}